package com.vzaar;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Encode/escape XML entities including unicode characters and so forth.
 * 
 * @author Marc G. Smith
 */
public class XmlEncoder 
{
	///////////////////////////////////////////////////////////////////////////
	// Private Methods ////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////

	private XmlEncoder() {
	}
	
	///////////////////////////////////////////////////////////////////////////
	// Public Methods /////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////

	/**
	 * Escape XML entities.
	 * 
	 * @param s the data to escape
	 * @return the escaped data
	 */
	public static final String encode(String s) {
		if(s == null) return null;
    	StringBuffer result = null;
		for(int i = 0, max = s.length(), delta = 0; i < max; i++) 
		{
			int c = s.charAt(i);
			String replacement = null;
		
			switch(c) {
				case '&': 	replacement = "&amp;"; break;
				case '<': 	replacement = "&lt;"; break;
				case '\r': 	replacement = "&#13;"; break;
				case '>': 	replacement = "&gt;"; break;
				case '"': 	replacement = "&quot;"; break;
				case '\'':  replacement = "&apos;"; break;
		        default:
		            if (c > 127) {
		              replacement = "&#" + escapeUnicode(c) + ";";
		            }					
			}
		
			if (replacement != null) {
				if (result == null) {
					result = new StringBuffer(s);
				}
				
				result.replace(i + delta, i + delta + 1, replacement);
				delta += (replacement.length() - 1);
			}
		}
		
		if (result == null) {
		    return s;
		}
		
		return result.toString();
	}

	///////////////////////////////////////////////////////////////////////////

	/**
	 * Decode XML entities.
	 * 
	 * @param line encoded string
	 * @return the decoded string
	 */
	public static String decode(String line) {
		if(line.contains("&apos;")) line = line.replaceAll("&apos;", "\'");
		if(line.contains("&quot;")) line = line.replaceAll("&quot;", "\"");
		if(line.contains("&gt;")) line = line.replaceAll("&gt;", ">");
		if(line.contains("&lt;")) line = line.replaceAll("&lt;", "<");
		if(line.contains("&#13;")) line = line.replaceAll("&#13;", "\r");
		if(line.contains("&amp;")) line = line.replaceAll("&amp;", "&");
		if(line.contains("&#")) {
			StringBuffer sb = new StringBuffer();
			Pattern p = Pattern.compile("&#([0-9]{3,4});");
			Matcher m = p.matcher(line);
			while(m.find()) {
				int ch = Integer.parseInt(m.group(1));
				m.appendReplacement(sb, String.valueOf((char) ch));
			}
			m.appendTail(sb);
			line = sb.toString();
		}
		return line;
	}

	///////////////////////////////////////////////////////////////////////////

	private static String escapeUnicode(int c) {
		String str = String.valueOf(c);
		if(str.length() == 1) return "00" + str;
		if(str.length() == 2) return "0" + str;
		return str;
	}

	///////////////////////////////////////////////////////////////////////////
}
